package com.easylinkin.linkappapi.airconditioner.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.airconditioner.entity.RegularTemperatureControlInfo;
import com.easylinkin.linkappapi.airconditioner.entity.ext.RefDeviceInfo;
import com.easylinkin.linkappapi.airconditioner.entity.ext.RegularTemperatureControlExt;
import com.easylinkin.linkappapi.airconditioner.mapper.TimingTemperatureControlMapper;
import com.easylinkin.linkappapi.airconditioner.service.TimingTemperatureControlService;
import com.easylinkin.linkappapi.airconditioner.util.CronExpressionUtil;
import com.easylinkin.linkappapi.common.constant.CommonConstant;
import com.easylinkin.linkappapi.common.exceptions.BusinessException;
import com.easylinkin.linkappapi.common.service.CommonService;
import com.easylinkin.linkappapi.common.utils.DateUtil;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.deviceservice.entity.DeviceServices;
import com.easylinkin.linkappapi.deviceservice.service.DeviceServiceService;
import com.easylinkin.linkappapi.linkage.entity.LinkageLog;
import com.easylinkin.linkappapi.linkage.mapper.LinkageLogMapper;
import com.easylinkin.linkappapi.openapi.dto.ApiDownResultDTO;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import com.easylinkin.linkappapi.taskscheduler.constant.JobEntityConstant;
import com.easylinkin.linkappapi.taskscheduler.entity.JobEntity;
import com.easylinkin.linkappapi.taskscheduler.service.JobEntityService;
import com.easylinkin.linkappapi.taskscheduler.service.TaskSchedulerService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

/**
 * class info :定时温控业务实现类
 *
 * @author liuqihang
 * @date 2021/5/8 18:19
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class TimingTemperatureControlServiceImpl extends ServiceImpl<TimingTemperatureControlMapper, RegularTemperatureControlExt> implements TimingTemperatureControlService, Job {

    @Resource
    LinkappUserContextProducer linkappUserContextProducer;

    @Resource
    private CommonService commonService;

    private static final String PREFIX = "regularTemperatureControl";

    private static final Logger LOGGER = LoggerFactory.getLogger(TimingTemperatureControlServiceImpl.class);


    @Resource
    TaskSchedulerService taskSchedulerService;

    @Resource
    JobEntityService jobEntityService;

    @Override
    public boolean add(RegularTemperatureControlExt regularTemperatureControlExt) {
        //获取租户
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        regularTemperatureControlExt.setTenantId(linkappUser.getTenantId());

        //检查重复名称
        validRepeat(new RegularTemperatureControlInfo()
                .setName(regularTemperatureControlExt.getName())
                .setTenantId(regularTemperatureControlExt.getTenantId()));
        //创建时间，创建人
        commonService.setCreateAndModifyInfo(regularTemperatureControlExt);

        String cronExpressionStr = CronExpressionUtil.generateAirCron(regularTemperatureControlExt.getStartTime(),
                regularTemperatureControlExt.getEndTime(), regularTemperatureControlExt.getExecuteTime());
        log.info("生成cron表达式：" + cronExpressionStr);
        regularTemperatureControlExt.setCronExpression(cronExpressionStr);
        regularTemperatureControlExt.setDeleteStatus(CommonConstant.ZERO);
        regularTemperatureControlExt.setStatus(CommonConstant.ONE);

        //保存
        baseMapper.addInfo(regularTemperatureControlExt);
        regularTemperatureControlExt.setRegularTciId(regularTemperatureControlExt.getId());

        String jobId = saveTask(regularTemperatureControlExt);
        regularTemperatureControlExt.setJobId(jobId);
        baseMapper.addDetail(regularTemperatureControlExt);

        //绑定设备和任务关联关系
        if(regularTemperatureControlExt.getDeviceIdList() != null && !regularTemperatureControlExt.getDeviceIdList().isEmpty()){
            bindTaskIdAndDeviceRef(regularTemperatureControlExt.getId(), regularTemperatureControlExt.getDeviceIdList());
        }
        return true;
    }

    @Override
    public boolean update(RegularTemperatureControlExt regularTemperatureControlExt) {
        //获取租户
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        regularTemperatureControlExt.setTenantId(linkappUser.getTenantId());

        //检查重复名称
        validRepeatExcludeSourceName(new RegularTemperatureControlInfo()
                .setId(regularTemperatureControlExt.getId())
                .setName(regularTemperatureControlExt.getName())
                .setTenantId(regularTemperatureControlExt.getTenantId()));

        //修改时间，修改人
        commonService.setModifyInfo(regularTemperatureControlExt);

        String cronExpressionStr = CronExpressionUtil.generateAirCron(regularTemperatureControlExt.getStartTime(),
                regularTemperatureControlExt.getEndTime(), regularTemperatureControlExt.getExecuteTime());
        log.info("生成cron表达式：" + cronExpressionStr);
        regularTemperatureControlExt.setCronExpression(cronExpressionStr);
        //保存
        baseMapper.updateInfo(regularTemperatureControlExt);
        regularTemperatureControlExt.setRegularTciId(regularTemperatureControlExt.getId());
        baseMapper.updateDetail(regularTemperatureControlExt);

        //绑定设备和任务关联关系
        if(regularTemperatureControlExt.getDeviceIdList() != null && !regularTemperatureControlExt.getDeviceIdList().isEmpty()){
            bindTaskIdAndDeviceRef(regularTemperatureControlExt.getId(), regularTemperatureControlExt.getDeviceIdList());
        }
        updateTask(regularTemperatureControlExt);

        return true;
    }

    @Override
    public boolean batchUpdateStatus(List<RegularTemperatureControlExt> rtceList) {
        for (RegularTemperatureControlExt rtce:
                rtceList) {
            if(rtce.getId() == null){
                return false;
            }
            if(rtce.getStatus() != null && rtce.getStatus().equals(0)){//禁用--暂停
                RegularTemperatureControlExt byId = baseMapper.getById(rtce.getId());
                JobEntity oldJob = jobEntityService.getById(byId.getJobId());
                //  一定要修改状态,不然禁用后还是会执行定时，消耗资源
                oldJob.setJobStatus(rtce.getStatus() + "");
                oldJob.setModifyTime(new Date());
                jobEntityService.updateById(oldJob);
                taskSchedulerService.pause(oldJob);
            }else if(rtce.getStatus() != null && rtce.getStatus().equals(1)){//启用
                RegularTemperatureControlExt byId = baseMapper.getById(rtce.getId());
                JobEntity oldJob = jobEntityService.getById(byId.getJobId());
                oldJob.setJobStatus(rtce.getStatus() + "");
                oldJob.setModifyTime(new Date());
                jobEntityService.updateById(oldJob);
                taskSchedulerService.resume(oldJob);
            }

            if(rtce.getDeleteStatus() != null && rtce.getDeleteStatus().equals(1)){//删除
                RegularTemperatureControlExt byId = baseMapper.getById(rtce.getId());
                JobEntity oldJob = jobEntityService.getById(byId.getJobId());
                QueryWrapper qw = new QueryWrapper();
                qw.eq("id", oldJob.getId());
                jobEntityService.remove(qw);
                taskSchedulerService.remove(oldJob);
            }
            baseMapper.updateStatus(rtce);
        }
        return true;
    }

    @Override
    public IPage<RegularTemperatureControlExt> getPage(Page page, RegularTemperatureControlExt rtce) {
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        rtce.setTenantId(linkappUser.getTenantId());
        IPage<RegularTemperatureControlExt> page1 = baseMapper.getPage(page, rtce);
        return page1;
    }

    @Override
    public RegularTemperatureControlExt getById(Long id) {
        RegularTemperatureControlExt byId = baseMapper.getById(id);

        List<Device> deviceInfoById = baseMapper.getDeviceInfoById(byId.getId());
        byId.setDeviceIdList(deviceInfoById);

        return byId;
    }

    private void validRepeat(RegularTemperatureControlInfo rtci) {
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        rtci.setTenantId(linkappUser.getTenantId());
        List<RegularTemperatureControlInfo> list = baseMapper.validRepeat(rtci);
        if (list.size() == 0) {
            return;
        }
        if (list.size() > 0) {
            throw new BusinessException("定时温控名称有重复");
        }
    }

    private void validRepeatExcludeSourceName(RegularTemperatureControlInfo rtci) {
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        rtci.setTenantId(linkappUser.getTenantId());
        List<RegularTemperatureControlInfo> list = baseMapper.validRepeatExcludeSourceName(rtci);
        if (list.size() == 0) {
            return;
        }
        if (list.size() > 1) {
            throw new BusinessException("定时温控名称有重复");
        }
    }

    private void bindTaskIdAndDeviceRef(Long id, List<Device> deviceList){
        baseMapper.unbindDevice(id);
        baseMapper.bindDevice(id, deviceList);
    }

    @Resource
    private DeviceServiceService deviceServiceService;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        String jobName = jobDetail.getKey().getName();
        String jobGroup = jobDetail.getKey().getGroup();
        log.info("定时温控---定时任务，任务分组：{}，任务名称：{}，任务触发时间：{}",
                jobGroup, jobName, DateUtil.getYYYYMMDDHHMMSSDate(new Date()));

        String parmString = jobDetail.getJobDataMap().getString("params");
        log.info("parmString=" + parmString);
        try{
            JSONObject  jsonObject = (JSONObject) JSON.parse(parmString);
            Long regularTemperatureControlId=jsonObject.getLong("regularTemperatureControlId");
            String executeData=jsonObject.getString("executeData");
            String weekExecuteFlag=jsonObject.getString("weekExecuteFlag");
            String notExecuteDate=jsonObject.getString("notExecuteDate");
            if("1".equals(weekExecuteFlag)){//周末不执行
                boolean weekend = DateUtil.isWeekend(new Date());
                if(weekend){
                    log.info("当前时间是周末时间，不执行任务");
                    return ;
                }
            }
            if(notExecuteDate != null && notExecuteDate.length() > 0){
                String format = DateUtil.format(new Date(), DateUtil.DATE_TIME_FORMAT_DAY);
                if(notExecuteDate.contains(format)){
                    log.info("当前时间在不执行日期内，不执行任务");
                    return ;
                }
            }

            RegularTemperatureControlExt byId = baseMapper.getById(regularTemperatureControlId);

            List<RefDeviceInfo> refDeviceInfoList = baseMapper.getRefDeviceInfo(regularTemperatureControlId);
            if(refDeviceInfoList != null && refDeviceInfoList.size() > 0){
                for (RefDeviceInfo rdi:
                        refDeviceInfoList) {
                    DeviceServices deviceServices = new DeviceServices();

                    Map<String, Object> downParameterMap = new HashMap<String, Object>(8);
                    Map<String, Object> executeeMap = JSON.parseObject(executeData, HashMap.class);

                    if(executeData.contains("lock_cmd") && executeeMap.size() > 1){//暂时处理
                        //发送锁定指令
                        Integer lockCmdValue = (Integer)executeeMap.get("lock_cmd");
                        Map<String, Object> lockCmdMap = new HashMap<String, Object>(8);
                        lockCmdMap.put("lock_cmd",lockCmdValue);
                        downParameterMap.put("device_id",rdi.getCode());
                        downParameterMap.put("parameter",lockCmdMap);
                        downParameterMap.put("service_id","air_conditioning_manage");
                        deviceServices.setDownParameter(downParameterMap);
                        log.info("推送指令参数：" + JSON.toJSONString(deviceServices));
                        ApiDownResultDTO send = deviceServiceService.send(deviceServices);
                        log.info("ApiDownResultDTO--响应结果" + JSON.toJSONString(send));
                        saveExecuteLog(send, jobName, rdi.getCode(), byId.getTenantId());
                        downParameterMap.clear();

                        //发送停止指令,默认补全其他默认值
                        executeeMap.remove("lock_cmd");
                        downParameterMap.put("device_id",rdi.getCode());
                        executeeMap.put("air_mode", "1");
                        executeeMap.put("air_wind_speed", "2");
                        executeeMap.put("air_temperature", 23);
                        downParameterMap.put("parameter",executeeMap);
                        downParameterMap.put("service_id","basic_mode_control");
                        deviceServices.setDownParameter(downParameterMap);
                        log.info("推送指令参数：" + JSON.toJSONString(deviceServices));
                        send = deviceServiceService.send(deviceServices);
                        log.info("ApiDownResultDTO--响应结果" + JSON.toJSONString(send));
                        saveExecuteLog(send, jobName, rdi.getCode(), byId.getTenantId());
                    }else if(!executeData.contains("lock_cmd")){
                        if(executeeMap.size() == 1 && executeeMap.containsKey("air_switch")){
                            executeeMap.put("air_mode", "1");
                            executeeMap.put("air_wind_speed", "2");
                            executeeMap.put("air_temperature", 23);
                        }
                        downParameterMap.put("device_id",rdi.getCode());
                        downParameterMap.put("parameter",executeData);
                        downParameterMap.put("service_id","basic_mode_control");
                        deviceServices.setDownParameter(downParameterMap);
                        log.info("推送指令参数：" + JSON.toJSONString(deviceServices));
                        ApiDownResultDTO send = deviceServiceService.send(deviceServices);
                        log.info("ApiDownResultDTO--响应结果" + JSON.toJSONString(send));
                        saveExecuteLog(send, jobName, rdi.getCode(), byId.getTenantId() );
                    }
                }
            }
        }catch(Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }


    @Resource
    private LinkageLogMapper linkageLogMapper;

    private void saveExecuteLog(ApiDownResultDTO send, String jobName, String deviceCode, String tenantId){
        LinkageLog ll = new LinkageLog();
        ll.setSendTime(new Date());
        ll.setSaveTime(new Date());
        ll.setDeviceCode(deviceCode);
        ll.setRuleEngineId(jobName);
        ll.setTenantId(tenantId);
        ll.setType(2);
        String code = send.getCode();
        ll.setState("0".equals(code) ? true : false);
        ll.setResultCode(send.getCode());
        ll.setResultMsg(send.getMsg());
        ll.setRequestId(send.getRequestId());
        linkageLogMapper.insert(ll);
    }

    private String saveTask(RegularTemperatureControlExt regularTemperatureControlExt){
        JobEntity jobEntity=new JobEntity();
        Date date = new Date();
        String jobGroup = PREFIX +"_"+ regularTemperatureControlExt.getTenantId();
        //尽量使得任务名称唯一 以防根据名称执行 会执行到多个任务
//        String jobName = PREFIXMODEL +"_"+regularTemperatureControlExt.getId() +"_"+ id;
        String jobName = UUID.randomUUID().toString().replaceAll("-", "");
        //查询原有Job
        QueryWrapper<JobEntity> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("job_name",jobName);
        queryWrapper.eq("job_group",jobGroup);
        JobEntity originJobEntity=jobEntityService.getOne(queryWrapper);
        if(originJobEntity != null){
            jobEntity=originJobEntity;
        }
        jobEntity.setJobGroup(jobGroup);
        jobEntity.setJobName(jobName);
        jobEntity.setCronExpression(regularTemperatureControlExt.getCronExpression());
//        jobEntity.setCronExpression("0 /5 * * * ? *");//调整5分钟运行一次
        jobEntity.setJobStatus(String.valueOf(regularTemperatureControlExt.getStatus()));
        jobEntity.setStartDate(DateUtil.getDateFromFormatStr(regularTemperatureControlExt.getStartTime() + " 00:00:00", DateUtil.DATE_TIME_FORMAT_DEFAULT));
        jobEntity.setEndDate(DateUtil.getDateFromFormatStr(regularTemperatureControlExt.getEndTime() + " 23:59:59", DateUtil.DATE_TIME_FORMAT_DEFAULT));

        jobEntity.setCreateTime(date);
        jobEntity.setModifyTime(date);
        jobEntity.setJobClassName(this.getClass().getName());
        //不立即运行
        jobEntity.setIsNowRun(JobEntityConstant.IsNowRunEnum.NO.getType());
        JSONObject parmObject = new JSONObject();
        parmObject.put("regularTemperatureControlId",regularTemperatureControlExt.getId());
        parmObject.put("startTime",regularTemperatureControlExt.getStartTime());
        parmObject.put("endTime",regularTemperatureControlExt.getEndTime());
        parmObject.put("executeTime",regularTemperatureControlExt.getExecuteTime());
        parmObject.put("executeData",regularTemperatureControlExt.getExecuteData());
        parmObject.put("weekExecuteFlag",regularTemperatureControlExt.getWeekExecuteFlag());
        parmObject.put("notExecuteDate",regularTemperatureControlExt.getNotExecuteDate());
        setJobEntityDefaultProperty(jobEntity);
        jobEntity.setParams(parmObject.toString());
        taskSchedulerService.saveOrUpdateTaskSetStartTime(jobEntity);
        return jobEntity.getId();
    }

    private void updateTask(RegularTemperatureControlExt regularTemperatureControlExt){
        Date dateFromFormatStr = DateUtil.getDateFromFormatStr(regularTemperatureControlExt.getEndTime(), DateUtil.DATE_TIME_FORMAT_DAY);
        log.info(System.currentTimeMillis() + ", " +dateFromFormatStr.getTime());
        if(System.currentTimeMillis() > dateFromFormatStr.getTime()){
            log.info("结束时间比当前时间小，不会被定时任务执行");
            return ;
        }

        JobEntity jobEntity=new JobEntity();
        RegularTemperatureControlExt byId = baseMapper.getById(regularTemperatureControlExt.getId());
        JobEntity originJobEntity = jobEntityService.getById(byId.getJobId());
        if(originJobEntity != null){
            jobEntity=originJobEntity;
        }

        jobEntity.setCronExpression(regularTemperatureControlExt.getCronExpression());
        if(regularTemperatureControlExt.getStatus() != null ){
            jobEntity.setJobStatus(String.valueOf(regularTemperatureControlExt.getStatus()));
        }

        jobEntity.setStartDate(DateUtil.getDateFromFormatStr(regularTemperatureControlExt.getStartTime() + " 00:00:00", DateUtil.DATE_TIME_FORMAT_DEFAULT));
        jobEntity.setEndDate(DateUtil.getDateFromFormatStr(regularTemperatureControlExt.getEndTime() + " 23:59:59", DateUtil.DATE_TIME_FORMAT_DEFAULT));

        jobEntity.setModifyTime(new Date());
        jobEntity.setJobClassName(this.getClass().getName());
        //不立即运行
        jobEntity.setIsNowRun(JobEntityConstant.IsNowRunEnum.NO.getType());
        JSONObject parmObject = new JSONObject();
        parmObject.put("regularTemperatureControlId",regularTemperatureControlExt.getId());
        parmObject.put("startTime",regularTemperatureControlExt.getStartTime());
        parmObject.put("endTime",regularTemperatureControlExt.getEndTime());
        parmObject.put("executeTime",regularTemperatureControlExt.getExecuteTime());
        parmObject.put("executeData",regularTemperatureControlExt.getExecuteData());
        parmObject.put("weekExecuteFlag",regularTemperatureControlExt.getWeekExecuteFlag());
        parmObject.put("notExecuteDate",regularTemperatureControlExt.getNotExecuteDate());
        setJobEntityDefaultProperty(jobEntity);
        jobEntity.setParams(parmObject.toString());
        taskSchedulerService.updateTask(jobEntity);
    }

    /**
     * 如果某些属性为空 给设置默认值
     */
    private void setJobEntityDefaultProperty(JobEntity jobEntity) {

        if (StringUtils.isEmpty(jobEntity.getJobTaskType())) {
            jobEntity.setJobTaskType(JobEntityConstant.JobTaskTypeEnum.API.getType());
        }
        if (StringUtils.isEmpty(jobEntity.getJobType())) {
            jobEntity.setJobType(JobEntityConstant.JobTypeEnum.CYCLE.getType());
        }
        if (StringUtils.isEmpty(jobEntity.getIsNowRun())) {
            jobEntity.setIsNowRun(JobEntityConstant.IsNowRunEnum.YES.getType());
        }
    }
}
